﻿
using System;
using Windows.UI.Xaml.Data;
namespace Calculator
{
    public class CalculatorEngine : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string _lastValue;
        private string _lastOp;
        private const string NumberFormatString = "0.###########";

        protected void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private void BinaryOperator(string op)
        {
            if (_currentValue == null)
            {
                _lastOp = op;
                return;
            }
            if (_lastOp == null)
            {
                PushCurrent();
                _lastOp = op;
                return;
            }
            else
            {
                EqualsOperator();
                _lastOp = op;
            }
        }

        private void PushCurrent()
        {
            if (_currentValue == null)
            {
                return;
            }
            LastValue = _currentValue;
            CurrentValue = null;
        }

        private void PopStack()
        {
            CurrentValue = _lastValue;
            _lastValue = null;
        }

        private void NegateCurrent()
        {
            if (_currentValue == null && _lastValue != null)
            {
                LastValue = Negate(_lastValue);
                return;
            }

            if (_currentValue == "0" || _currentValue == null)
            {
                return;
            }
            CurrentValue = Negate(_currentValue);
        }

        private static string Negate(string val)
        {
            if (val.StartsWith("-"))
            {
                return val.Substring(1);
            }
            else
            {
                return "-" + val;
            }
        }

        private void AppendCurrent(string str)
        {
            if (str == ".")
            {
                if (_currentValue == null)
                {
                    CurrentValue = "0.";
                    return;
                }
                if (_currentValue.Contains("."))
                {
                    return;
                }
            }
            if (_currentValue == "0")
            {
                CurrentValue = str;
            }
            else
            {
                CurrentValue = _currentValue + str;
            }
        }

        private string _currentValue;
        public string CurrentValue
        {
            get { return _currentValue != null ? _currentValue : (_lastValue != null ? _lastValue : "0"); }
            set { if (_currentValue != value) { _currentValue = value; OnPropertyChanged("CurrentValue"); } }
        }

        public string LastValue
        {
            set { if (_lastValue != value) { _lastValue = value; OnPropertyChanged("LastValue"); OnPropertyChanged("CurrentValue"); } }
        }

        public double CurrentValueDouble
        {
            set { _currentValue = value.ToString(NumberFormatString); }
        }

        public void ProcessKey(string func)
        {
            switch (func)
            {
                case "0": AppendCurrent("0"); break;
                case "1": AppendCurrent("1"); break;
                case "2": AppendCurrent("2"); break;
                case "3": AppendCurrent("3"); break;
                case "4": AppendCurrent("4"); break;
                case "5": AppendCurrent("5"); break;
                case "6": AppendCurrent("6"); break;
                case "7": AppendCurrent("7"); break;
                case "8": AppendCurrent("8"); break;
                case "9": AppendCurrent("9"); break;
                case ".": AppendCurrent("."); break;
                case "+/-": NegateCurrent(); break;
                case "/": BinaryOperator("/"); break;
                case "*": BinaryOperator("*"); break;
                case "-": BinaryOperator("-"); break;
                case "+": BinaryOperator("+"); break;
                case "=": EqualsOperator(); break;
                case "C": Clear(); break;
                case "CE": ClearEverything(); break;
                case "1/x": Reciprical(); break;
                case "<-": Backspace(); break;
                default:
                    throw new Exception("Invalid key press");
            }
        }

        private void Backspace()
        {
            if (_currentValue != null)
            {
                if (_currentValue.Length > 0)
                {
                    CurrentValue = _currentValue.Substring(0, _currentValue.Length - 1);
                }
            }
            else if (_lastValue != null)
            {
                if (_lastValue.Length > 0)
                {
                    LastValue = _lastValue.Substring(0, _lastValue.Length - 1);
                }
            }
            else
            {
                throw new Exception("Value is empty");
            }
        }

        private void Reciprical()
        {
            if (_currentValue != null)
            {
                CurrentValue = Reciprical(_currentValue);
            }
            else if (_lastValue != null)
            {
                LastValue = Reciprical(_lastValue);
            }
        }

        private static string Reciprical(string val)
        {
            return (1.0 / double.Parse(val)).ToString(NumberFormatString);
        }

        private void ClearEverything()
        {
            _lastOp = null;
            LastValue = null;
            CurrentValue = "0";
        }

        private void Clear()
        {
            if (_currentValue != null)
            {
                CurrentValue = null;
                return;
            }
            if (_lastValue != null)
            {
                LastValue = "0";
            }
        }

        private void EqualsOperator()
        {
            if (_lastOp == null)
            {
                return;
            }

            double stackTop = double.Parse(_lastValue);
            double current = double.Parse(_currentValue);
            double result;
            switch (_lastOp)
            {
                case "+": result = stackTop + current; break;
                case "-": result = stackTop - current; break;
                case "*": result = stackTop * current; break;
                case "/": result = stackTop / current; break;
                default:
                    throw new Exception("Invalid operator");
            }
            CurrentValueDouble = result;
            PushCurrent();
            _lastOp = null;
        }
    }
}
